package org.suwenqian.audiovideosummary.service.llm;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.suwenqian.audiovideosummary.common.enums.ProcessStepEnum;
import org.suwenqian.audiovideosummary.config.LLMProperties;
import org.suwenqian.audiovideosummary.dao.entity.Chapter;
import org.suwenqian.audiovideosummary.dao.entity.ProgressLog;
import org.suwenqian.audiovideosummary.dao.entity.Result;
import org.suwenqian.audiovideosummary.dao.mapper.ProgressLogMapper;
import org.suwenqian.audiovideosummary.dao.mapper.ResultMapper;
import org.suwenqian.audiovideosummary.dto.req.AsrEndReqDTO;
import org.suwenqian.audiovideosummary.dto.resp.OutlineDTO;
import org.suwenqian.audiovideosummary.exception.LLMServiceException;
import org.suwenqian.audiovideosummary.service.ProgressLogService;
import org.suwenqian.audiovideosummary.util.LLMUtil;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class LLMService {

    private final LLMProperties props;
    private final LLMUtil util;
    private final ResultMapper resultMapper;
    private final ProgressLogMapper progressLogMapper;
    private final ProgressLogService progressLogService;

    @Async("asyncExecutor")
    public void doLLM(AsrEndReqDTO requestParam) {
        try {
            Snowflake snowflake = new Snowflake(0, 0);
            // 1. 读取文本文件内容
            String fullText = new String(requestParam.getFile().getBytes(), StandardCharsets.UTF_8);

            // 2. 使用滑动窗口切分文本
            List<String> chunks = splitWindow(fullText, props.getWindow());

            // 3. 并行调用摘要生成接口
            List<String> summaries = chunks.parallelStream()
                    .map(chunk -> {
                        try {
                            return util.callSummary(chunk);
                        } catch (LLMServiceException e) {
                            log.error("[生成摘要失败]--生成摘要文本大纲与思维导图任务--{} -- 处理失败: {}", requestParam.getTaskId(),e.getMessage());
                            return ""; // 返回空字符串作为失败占位符
                        }
                    })
                    .filter(summary -> !summary.isEmpty()) // 过滤掉失败的结果
                    .collect(Collectors.toList());

            // 合并所有摘要
            String combinedSummary = String.join("\n", summaries);

            // 4. 调用大纲提取接口
            OutlineDTO outline = util.callOutline(fullText);
            String mindMapMd = buildMarkMapMD(combinedSummary, outline.getChapters(), outline.getKeywords());

            // 5. 保存结果到数据库
            Result result  = Result.builder()
                    .id(snowflake.nextId())
                    .fullText(fullText)
                    .summary(combinedSummary)
                    .taskId(requestParam.getTaskId())
                    .createdAt(new Date())
                    .versionNo(1)
                    .keywordsJson(outline.getKeywords())
                    .outlineJson(outline.getChapters())
                    .mindMapMd(mindMapMd)
                    .costTimeMs(outline.getCost())
                    .build();
            resultMapper.insert(result);

            Optional.ofNullable(progressLogMapper.selectOne(
                    Wrappers.lambdaQuery(ProgressLog.class)
                            .eq(ProgressLog::getTaskId, requestParam.getTaskId())
            )).ifPresent(log -> {
                log.setStep(ProcessStepEnum.LLM);
                log.setPercent(ProcessStepEnum.LLM.getPercent());
                log.setMessage(ProcessStepEnum.LLM.getDescription());
                progressLogService.sendProgress(log);
            });
            log.info("[大模型音频处理]--生成摘要文本大纲与思维导图任务：--{}-- 已完成", requestParam.getTaskId());

            Optional.ofNullable(progressLogMapper.selectOne(
                    Wrappers.lambdaQuery(ProgressLog.class)
                            .eq(ProgressLog::getTaskId, requestParam.getTaskId())
            )).ifPresent(log -> {
                log.setStep(ProcessStepEnum.MIND_MAP);
                log.setPercent(ProcessStepEnum.MIND_MAP.getPercent());
                log.setMessage(ProcessStepEnum.MIND_MAP.getDescription());
                progressLogService.sendProgress(log);
            });

        } catch (IOException e) {
            log.error("[读取文件失败]--生成摘要文本大纲与思维导图任务--{} -- 处理失败: {}", requestParam.getTaskId(), e.getMessage());
        } catch (LLMServiceException e) {
            log.error("[大模型音频处理]--生成摘要文本大纲与思维导图任务--{} -- 大模型调用发生错误: {}", requestParam.getTaskId(), e.getMessage());
        } catch (Exception e) {
            log.error("[大模型音频处理]--生成摘要文本大纲与思维导图任务--{} -- 处理失败：{}", requestParam.getTaskId(), e.getMessage());
        }
    }

    /**
     * 滑动窗口切分文本
     */
    private List<String> splitWindow(String text, int window) {
        List<String> list = new ArrayList<>();
        int len = text.length();
        for (int i = 0; i < len; i += window) {
            list.add(text.substring(i, Math.min(i + window, len)));
        }
        return list;
    }

    /**
     * 思维导图生成，JSON返回前段渲染
     * @param summary 摘要
     * @param chapters 章节
     * @param keywords 关键字
     * @return 返回脑图JSON
     */
    private static String buildMarkMapMD(String summary,
                                         List<Chapter> chapters,
                                         List<String> keywords) {
        StringBuilder sb = new StringBuilder();
        sb.append("# ").append(summary).append("\n");
        for (Chapter c : chapters) {
            sb.append("## ").append(c.getTitle()).append("\n");
        }
        sb.append("## 关键词\n");
        keywords.forEach(k -> sb.append("- ").append(k).append("\n"));
        return sb.toString();
    }

}